<!DOCTYPE html>
<html  lang="zh-CN" >
    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, minimum-scale=1, initial-scale=1, maximum-scale=5, viewport-fit=cover">
    <title>ESP-IDF学习笔记-MQTT客户端 | LO_StacNet的火柴盒</title>
    <meta name="description" content="先上官方文档 参考文献 一，MQTT协议的简介网上很多这里不作讲解，参考这篇文章 二，ESP_MQTT的配置过程ESP_MQTT实现了MQTT客户端的功能，支持多种协议，这里仅以TCp为例。基本步骤如下;  使用esp_mqtt_client_init()配置mqtt。 使用esp_mqtt_client_register_event()注册事件处理函数。 使用esp_mqtt_client_">
<meta property="og:type" content="article">
<meta property="og:title" content="ESP-IDF学习笔记-MQTT客户端">
<meta property="og:url" content="https://lostacnet.top/post/5349/">
<meta property="og:site_name" content="LO_StacNet的火柴盒">
<meta property="og:description" content="先上官方文档 参考文献 一，MQTT协议的简介网上很多这里不作讲解，参考这篇文章 二，ESP_MQTT的配置过程ESP_MQTT实现了MQTT客户端的功能，支持多种协议，这里仅以TCp为例。基本步骤如下;  使用esp_mqtt_client_init()配置mqtt。 使用esp_mqtt_client_register_event()注册事件处理函数。 使用esp_mqtt_client_">
<meta property="og:locale" content="zh_CN">
<meta property="article:published_time" content="2023-05-03T07:49:05.000Z">
<meta property="article:modified_time" content="2023-05-29T15:34:17.208Z">
<meta property="article:author" content="LO_StacNet">
<meta property="article:tag" content="ESP-IDF">
<meta property="article:tag" content="ESP32">
<meta property="article:tag" content="MQTT">
<meta name="twitter:card" content="summary">

    
    <link rel="icon" href="/images/favicon.ico" type="image/x-icon">

    
<link rel="stylesheet" href="/css/common.min.css">



    
        <link href="//cdn.jsdelivr.net/npm/katex@0.9.0/dist/katex.min.css" rel="stylesheet">
    
    
    
    
        <link href="//cdn.jsdelivr.net/npm/lightgallery.js@1.1.3/dist/css/lightgallery.min.css" rel="stylesheet">
    
    
    
<link rel="stylesheet" href="/css/iconfont.min.css">

    
<meta name="generator" content="Hexo 6.3.0"><style>mjx-container[jax="SVG"] {
  direction: ltr;
}

mjx-container[jax="SVG"] > svg {
  overflow: visible;
}

mjx-container[jax="SVG"][display="true"] {
  display: block;
  text-align: center;
  margin: 1em 0;
}

mjx-container[jax="SVG"][justify="left"] {
  text-align: left;
}

mjx-container[jax="SVG"][justify="right"] {
  text-align: right;
}

g[data-mml-node="merror"] > g {
  fill: red;
  stroke: red;
}

g[data-mml-node="merror"] > rect[data-background] {
  fill: yellow;
  stroke: none;
}

g[data-mml-node="mtable"] > line[data-line] {
  stroke-width: 70px;
  fill: none;
}

g[data-mml-node="mtable"] > rect[data-frame] {
  stroke-width: 70px;
  fill: none;
}

g[data-mml-node="mtable"] > .mjx-dashed {
  stroke-dasharray: 140;
}

g[data-mml-node="mtable"] > .mjx-dotted {
  stroke-linecap: round;
  stroke-dasharray: 0,140;
}

g[data-mml-node="mtable"] > svg {
  overflow: visible;
}

[jax="SVG"] mjx-tool {
  display: inline-block;
  position: relative;
  width: 0;
  height: 0;
}

[jax="SVG"] mjx-tool > mjx-tip {
  position: absolute;
  top: 0;
  left: 0;
}

mjx-tool > mjx-tip {
  display: inline-block;
  padding: .2em;
  border: 1px solid #888;
  font-size: 70%;
  background-color: #F8F8F8;
  color: black;
  box-shadow: 2px 2px 5px #AAAAAA;
}

g[data-mml-node="maction"][data-toggle] {
  cursor: pointer;
}

mjx-status {
  display: block;
  position: fixed;
  left: 1em;
  bottom: 1em;
  min-width: 25%;
  padding: .2em .4em;
  border: 1px solid #888;
  font-size: 90%;
  background-color: #F8F8F8;
  color: black;
}

foreignObject[data-mjx-xml] {
  font-family: initial;
  line-height: normal;
  overflow: visible;
}

.MathJax path {
  stroke-width: 3;
}

mjx-container[display="true"] {
  overflow: auto hidden;
}

mjx-container[display="true"] + br {
  display: none;
}
</style></head>

    <body>
        <header class="header header-fixture">
    <div class="profile-search-wrap flex sm:block">
        
        
        <div class="profile sm:text-center md:px-1 lg:px-3 sm:pb-4 sm:pt-6">
            <a id="avatar" role="link" href="http://www.lostacnet.top" class="inline-block lg:w-16 lg:h-16 w-8 h-8 m-2" target="_blank" rel="noopener" rel="noreferrer" >
                <img src="/images/avatar.jpg" class="rounded-full" alt="avatar">
            </a>
            <h2 id="name" class="hidden lg:block">LO_StacNet</h2>
            <h3 id="title" class="hidden lg:block">电子玩家 &amp; 理想主义</h3>
            
            <small id="location" class="hidden lg:block">
                <i class="iconfont icon-map-icon"></i>
                Sichuan, China
            </small>
            
        </div>
        
        
<div class="search flex-1 flex lg:inline-block sm:hidden lg:px-4 lg:mt-2 lg:mb-4 lg:w-full">
    <form id="search-form" class="my-auto flex-1 lg:border lg:border-solid lg:border-gray-200">
        <div class="input-group table bg-gray-100 lg:bg-white w-full">
            <input id="search-input" type="text" placeholder="搜索" class="inline-block w-full bg-gray-100 lg:bg-white p-1">
            <span class="table-cell">
                <button name="search tigger button" disabled>
                    <i class="iconfont icon-search m-2"></i>
                </button>
            </span>
        </div>
    </form>
        
<div id="content-json" data-placeholder="搜索" class="invisible hidden">/content.json</div>
<script id="search-teamplate" type="text/html" data-path="/content.json">
    <div>
        <div class="search-header bg-gray-400">
            <input id="actual-search-input" model="keyword" ref="input" class="inline-block w-full h-10 px-2 py-1" placeholder="搜索" type="text">
        </div>
        <div class="search-result bg-gray-200">
            {{#each searchPosts}}
            <a href="/{{ path }}" class="result-item block px-2 pb-3 mb-1 pt-1 hover:bg-indigo-100">
                <i class="iconfont icon-file"></i>
                <h1 class="result-title inline font-medium text-lg">{{ title }}</h1>
                <p class="result-content text-gray-600 text-sm">{{{ text }}}</p>
            </a>
            {{/each}}
        </div>
    </div>
</script>

</div>


        <button name="menu toogle button" id="menu-toggle-btn" class="block sm:hidden p-3" role="button" aria-expanded="false">
            <i class="iconfont icon-hamburger"></i>
        </button>
    </div>
    <nav id="menu-nav" class="hidden sm:flex flex-col">
        
        
            <div class="menu-item menu-home" role="menuitem">
                <a href="/.">
                    <i class="iconfont icon-home" aria-hidden="true"></i>
                    <span class="menu-title">首页</span>
                </a>
            </div>
        
        
            <div class="menu-item menu-archives" role="menuitem">
                <a href="/archives">
                    <i class="iconfont icon-archive" aria-hidden="true"></i>
                    <span class="menu-title">归档</span>
                </a>
            </div>
        
        
            <div class="menu-item menu-categories" role="menuitem">
                <a href="/categories">
                    <i class="iconfont icon-folder" aria-hidden="true"></i>
                    <span class="menu-title">分类</span>
                </a>
            </div>
        
        
            <div class="menu-item menu-tags" role="menuitem">
                <a href="/tags">
                    <i class="iconfont icon-tag" aria-hidden="true"></i>
                    <span class="menu-title">标签</span>
                </a>
            </div>
        
        
            <div class="menu-item menu-links" role="menuitem">
                <a href="/links">
                    <i class="iconfont icon-friend" aria-hidden="true"></i>
                    <span class="menu-title">友链</span>
                </a>
            </div>
        
        
            <div class="menu-item menu-about" role="menuitem">
                <a href="/about">
                    <i class="iconfont icon-cup" aria-hidden="true"></i>
                    <span class="menu-title">关于</span>
                </a>
            </div>
        
        
<div class="social-links flex sm:flex-col lg:hidden mt-5">
    
        <span class="social-item text-center">
            <a target="_blank" rel="noopener" href="https://github.com/LOStacNet">
                <i class="iconfont social-icon icon-github"></i>
                <span class="menu-title hidden lg:inline">menu.github</span>
            </a>
        </span>
    
        <span class="social-item text-center">
            <a target="_blank" rel="noopener" href="https://gitee.com/LOStacNet">
                <i class="iconfont social-icon icon-project"></i>
                <span class="menu-title hidden lg:inline">menu.project</span>
            </a>
        </span>
    
</div>


    </nav>
</header>

        <section class="main-section">
            
    <main class="flex-1 px-4 py-14 md:px-5 lg:px-8 lg:py-4 relative min-h-screen">
    

    <article class="content article article-archives article-type-list" itemscope="">
        <header class="article-header">
            
    
        <h1 class="article-title text-lg" itemprop="name">
            ESP-IDF学习笔记-MQTT客户端
        </h1>
    



            <p class="article-meta mb-3 text-xs">
                <span class="article-date">
    <i class="iconfont icon-calendar-check"></i>
	<a href="/post/5349/" class="article-date">
	  <time datetime="2023-05-03T07:49:05.000Z" itemprop="datePublished">5月 3</time>
	</a>
</span>

                
    <span class="article-category">
    <i class="iconfont icon-folder"></i>
    <a class="article-category-link" href="/categories/ESP32%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/">ESP32学习笔记</a>
  </span>


                
    <span class="article-tags">
    <i class="iconfont icon-tag"></i>
    <a class="article-tag-none-link" href="/tags/ESP-IDF/" rel="tag">ESP-IDF</a>, <a class="article-tag-none-link" href="/tags/ESP32/" rel="tag">ESP32</a>, <a class="article-tag-none-link" href="/tags/MQTT/" rel="tag">MQTT</a>
  </span>


                <span class="_partial/post-comment"><i class="icon icon-comment"></i>
                    <a href="/post/5349/#comments" class="article-comment-link">
                        评论
                    </a>
                </span>
                
    
        <span class="post-wordcount" itemprop="wordCount">字数统计: 3.3k(字)</span>
    
    
        <span class="post-readcount" itemprop="timeRequired">阅读时长: 14(分)</span>
    


            </p>
        </header>
        <div class="marked-body article-body">
            <span id="more"></span>

<p>先上<a target="_blank" rel="noopener" href="https://docs.espressif.com/projects/esp-idf/zh_CN/latest/esp32s3/api-reference/protocols/mqtt.html#mqtt">官方文档</a></p>
<p><a target="_blank" rel="noopener" href="https://blog.csdn.net/m0_50064262/article/details/126499263">参考文献</a></p>
<h2 id="一，MQTT协议的简介"><a href="#一，MQTT协议的简介" class="headerlink" title="一，MQTT协议的简介"></a>一，MQTT协议的简介</h2><p>网上很多这里不作讲解，参考<a target="_blank" rel="noopener" href="https://zhuanlan.zhihu.com/p/421109780">这篇文章</a></p>
<h2 id="二，ESP-MQTT的配置过程"><a href="#二，ESP-MQTT的配置过程" class="headerlink" title="二，ESP_MQTT的配置过程"></a>二，ESP_MQTT的配置过程</h2><p>ESP_MQTT实现了MQTT客户端的功能，支持多种协议，这里仅以TCp为例。基本步骤如下;</p>
<ol>
<li>使用<code>esp_mqtt_client_init()</code>配置mqtt。</li>
<li>使用<code>esp_mqtt_client_register_event()</code>注册事件处理函数。</li>
<li>使用<code>esp_mqtt_client_start()</code>开启mqtt客户端。</li>
</ol>
<p><strong>MQTT的运行</strong>与WiFi类似，都是<strong>基于事件进行处理</strong>。但是，WiFi库是基于<code>ESP_EVENT</code>库而MQTT库则是使用的内建的事件处理循环。</p>
<h3 id="初始化MQTT"><a href="#初始化MQTT" class="headerlink" title="初始化MQTT"></a>初始化MQTT</h3><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">esp_mqtt_client_handle_t</span> <span class="title function_">esp_mqtt_client_init</span><span class="params">(<span class="type">const</span> <span class="type">esp_mqtt_client_config_t</span> *config)</span>;</span><br></pre></td></tr></table></figure>

<p>使用该函数初始化MQTT客户端，并创建MQTT客户端句柄。</p>
<ul>
<li><code>esp_mqtt_client_config_t</code></li>
</ul>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">typedef</span> <span class="class"><span class="keyword">struct</span> <span class="title">esp_mqtt_client_config_t</span> {</span></span><br><span class="line">  <span class="comment">/**</span></span><br><span class="line"><span class="comment">   *   Broker 相关设置</span></span><br><span class="line"><span class="comment">   */</span></span><br><span class="line">  <span class="class"><span class="keyword">struct</span> <span class="title">broker_t</span> {</span></span><br><span class="line">      <span class="comment">/**</span></span><br><span class="line"><span class="comment">       * Broker address</span></span><br><span class="line"><span class="comment">       *</span></span><br><span class="line"><span class="comment">       *  - uri 优先于其他字段</span></span><br><span class="line"><span class="comment">       *  - 如果uri没有设置，至少hostname, transport and port 应该被设置.</span></span><br><span class="line"><span class="comment">       */</span></span><br><span class="line">      <span class="class"><span class="keyword">struct</span> <span class="title">address_t</span> {</span></span><br><span class="line">          <span class="type">const</span> <span class="type">char</span> *uri; <span class="comment">/*!&lt; 完整的 *MQTT* broker URI */</span></span><br><span class="line">          <span class="type">const</span> <span class="type">char</span> *hostname; <span class="comment">/*!&lt; Hostname, to set ipv4 pass it as string) */</span></span><br><span class="line">          <span class="type">esp_mqtt_transport_t</span> transport; <span class="comment">/*!&lt; 选择协议类型*/</span></span><br><span class="line">          <span class="type">const</span> <span class="type">char</span> *path;               <span class="comment">/*!&lt; Path in the URI*/</span></span><br><span class="line">          <span class="type">uint32_t</span> port;                  <span class="comment">/*!&lt; *MQTT* server port */</span></span><br><span class="line">      } address; <span class="comment">/*!&lt; Broker地址设置 */</span></span><br><span class="line">      <span class="comment">/**</span></span><br><span class="line"><span class="comment">       * Broker 的身份验证</span></span><br><span class="line"><span class="comment">       *</span></span><br><span class="line"><span class="comment">       * 如果不设置这部分，将不会验证Broker的身份，为安全考虑建议设置验证</span></span><br><span class="line"><span class="comment">       */</span></span><br><span class="line">      <span class="class"><span class="keyword">struct</span> <span class="title">verification_t</span> {</span></span><br><span class="line">          <span class="type">bool</span> use_global_ca_store; <span class="comment">/*!&lt; 是否使用全局 ca_store, 详见 esp-tls文档*/</span></span><br><span class="line">          <span class="type">esp_err_t</span> (*crt_bundle_attach)(<span class="type">void</span> *conf); <span class="comment">/*!&lt; Pointer to ESP x509 Certificate Bundle attach function for</span></span><br><span class="line"><span class="comment">                                                the usage of certificate bundles. */</span></span><br><span class="line">          <span class="type">const</span> <span class="type">char</span> *certificate; <span class="comment">/*!&lt; 证书数据，默认为NULL，验证服务器时不需要. */</span></span><br><span class="line">          <span class="type">size_t</span> certificate_len; <span class="comment">/*!&lt; 证书数据长度 */</span></span><br><span class="line">          <span class="type">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">psk_key_hint</span> *<span class="title">psk_hint_key</span>;</span> <span class="comment">/*!&lt; 指向esp_tls.h中定义的PSK结构的指针，以启用PSK 认证（作为证书验证的替代）.</span></span><br><span class="line"><span class="comment">          											只有当没有其他验证方式时启用*/</span></span><br><span class="line">          <span class="type">bool</span> skip_cert_common_name_check; <span class="comment">/*!&lt; 跳过对服务器证书CN字段的任何验证，这降低了TLS的安全性，使*MQTT*客户端容易受到MITM攻击  */</span></span><br><span class="line">          <span class="type">const</span> <span class="type">char</span> **alpn_protos;        <span class="comment">/*!&lt; 用于ALPN的以NULL为结尾的支持应用协议列表 */</span></span><br><span class="line">      } verification; <span class="comment">/*!&lt;  broker的身份验证 */</span></span><br><span class="line">  } broker; <span class="comment">/*!&lt; Broker 地址和验证信息 */</span></span><br><span class="line">  <span class="comment">/**</span></span><br><span class="line"><span class="comment">   * Client related credentials for authentication.</span></span><br><span class="line"><span class="comment">   */</span></span><br><span class="line">  <span class="class"><span class="keyword">struct</span> <span class="title">credentials_t</span> {</span></span><br><span class="line">      <span class="type">const</span> <span class="type">char</span> *username;    <span class="comment">/*!&lt; *MQTT* 用户名*/</span></span><br><span class="line">      <span class="type">const</span> <span class="type">char</span> *client_id;   <span class="comment">/*!&lt; 设置 *MQTT* 客户端ID. 如果 set_null_client_id == true 忽略. 如果是NULL则为默认设置. Default client id is ``ESP32_%CHIPID%`` where `%CHIPID%` are last 3 bytes of MAC address in hex format */</span></span><br><span class="line">      <span class="type">bool</span> set_null_client_id; <span class="comment">/*!&lt; 用户ID是否为NULL */</span></span><br><span class="line">      <span class="comment">/**</span></span><br><span class="line"><span class="comment">       * 客户端验证</span></span><br><span class="line"><span class="comment">       *</span></span><br><span class="line"><span class="comment">       * 对于使用TLS的相互认证，用户可以选择证书和密钥,</span></span><br><span class="line"><span class="comment">       * 安全认证信息（如果设置了）.</span></span><br><span class="line"><span class="comment">       *</span></span><br><span class="line"><span class="comment">       */</span></span><br><span class="line">      <span class="class"><span class="keyword">struct</span> <span class="title">authentication_t</span> {</span></span><br><span class="line">          <span class="type">const</span> <span class="type">char</span> *password;    <span class="comment">/*!&lt; *MQTT* 密码 */</span></span><br><span class="line">          <span class="type">const</span> <span class="type">char</span> *certificate; <span class="comment">/*!&lt; ssl认证的证书, 需要与key一起提供.如果没有验证则不需要*/</span></span><br><span class="line">          <span class="type">size_t</span> certificate_len;  <span class="comment">/*!&lt; 证书的长度.*/</span></span><br><span class="line">          <span class="type">const</span> <span class="type">char</span> *key;       <span class="comment">/*!&lt; ssl认证的私钥，需要与证书一起提供，如果没有验证则不需要*/</span></span><br><span class="line">          <span class="type">size_t</span> key_len; <span class="comment">/*!&lt; key的长度.*/</span></span><br><span class="line">          <span class="type">const</span> <span class="type">char</span> *key_password; <span class="comment">/*!&lt; 客户端密钥解密密码，不是PEM也不是DER, 如果提供，len也必须正确提供. */</span></span><br><span class="line">          <span class="type">int</span> key_password_len;    <span class="comment">/*!&lt;  `key_password`的长度 */</span></span><br><span class="line">          <span class="type">bool</span> use_secure_element; <span class="comment">/*!&lt; 启用安全元素，在ESP32-ROOM-32SE中可用，用于SSL连接。 */</span></span><br><span class="line">          <span class="type">void</span> *ds_data; <span class="comment">/*!&lt; 数字签名，数字签名外设在一些Espressif设备中是可用的。 */</span></span><br><span class="line">      } authentication; <span class="comment">/*!&lt; 用户验证信息 */</span></span><br><span class="line">  } credentials; <span class="comment">/*!&lt; 用户验证信息 */</span></span><br><span class="line">  <span class="comment">/**</span></span><br><span class="line"><span class="comment">   * *MQTT* 会话相关设置</span></span><br><span class="line"><span class="comment">   */</span></span><br><span class="line">  <span class="class"><span class="keyword">struct</span> <span class="title">session_t</span> {</span></span><br><span class="line">      <span class="comment">/**</span></span><br><span class="line"><span class="comment">       * 遗嘱设置.</span></span><br><span class="line"><span class="comment">       */</span></span><br><span class="line">      <span class="class"><span class="keyword">struct</span> <span class="title">last_will_t</span> {</span></span><br><span class="line">          <span class="type">const</span> <span class="type">char</span> *topic; <span class="comment">/*!&lt; 遗嘱消息的主题 */</span></span><br><span class="line">          <span class="type">const</span> <span class="type">char</span> *msg; <span class="comment">/*!&lt; 遗嘱消息，以NULL空字符结尾*/</span></span><br><span class="line">          <span class="type">int</span> msg_len; <span class="comment">/*!&lt; 遗嘱长度，如果msg不以NULL结尾，需要设置正确长度 */</span></span><br><span class="line">          <span class="type">int</span> qos;     <span class="comment">/*!&lt; 遗嘱消息质量 */</span></span><br><span class="line">          <span class="type">int</span> retain;  <span class="comment">/*!&lt; 遗嘱保留标志 */</span></span><br><span class="line">      } last_will; <span class="comment">/*!&lt; 遗嘱设置 */</span></span><br><span class="line">      <span class="type">bool</span> disable_clean_session; <span class="comment">/*!&lt; *MQTT* 持久会话设置， */</span></span><br><span class="line">      <span class="type">int</span> keepalive;              <span class="comment">/*!&lt; *MQTT* keepalive时间, 默认 120 seconds */</span></span><br><span class="line">      <span class="type">bool</span> disable_keepalive; <span class="comment">/*!&lt; 设置 `disable_keepalive=true` 来关闭 keep-alive, keepalive 默认开启. </span></span><br><span class="line"><span class="comment">      					Note: 设置keepalive为0不会关闭keepalive，而是使用默认的时间长度 */</span></span><br><span class="line">      <span class="type">esp_mqtt_protocol_ver_t</span> protocol_ver; <span class="comment">/*!&lt; *MQTT* 使用的协议版本.*/</span></span><br><span class="line">      <span class="type">int</span> message_retransmit_timeout; <span class="comment">/*!&lt; 重传超时时间 */</span></span><br><span class="line">  } session; <span class="comment">/*!&lt; *MQTT* 会话设置. */</span></span><br><span class="line">  <span class="comment">/**</span></span><br><span class="line"><span class="comment">   * 网络相关设置</span></span><br><span class="line"><span class="comment">   */</span></span><br><span class="line">  <span class="class"><span class="keyword">struct</span> <span class="title">network_t</span> {</span></span><br><span class="line">      <span class="type">int</span> reconnect_timeout_ms; <span class="comment">/*!&lt; 断开连接后重新自动连接到broker间隔的时间，默认为10s*/</span></span><br><span class="line">      <span class="type">int</span> timeout_ms; <span class="comment">/*!&lt; 网络操作超时时间，默认10s. */</span></span><br><span class="line">      <span class="type">int</span> refresh_connection_after_ms; <span class="comment">/*!&lt; 刷新连接事件间隔 */</span></span><br><span class="line">      <span class="type">bool</span> disable_auto_reconnect;     <span class="comment">/*!&lt; 设置为true关闭自动重连 */</span></span><br><span class="line">  } network; <span class="comment">/*!&lt; 网络设置 */</span></span><br><span class="line">  <span class="comment">/**</span></span><br><span class="line"><span class="comment">   * 客户端任务设置</span></span><br><span class="line"><span class="comment">   */</span></span><br><span class="line">  <span class="class"><span class="keyword">struct</span> <span class="title">task_t</span> {</span></span><br><span class="line">      <span class="type">int</span> priority;   <span class="comment">/*!&lt; *MQTT* 任务优先级*/</span></span><br><span class="line">      <span class="type">int</span> stack_size; <span class="comment">/*!&lt; *MQTT* 任务栈大小*/</span></span><br><span class="line">  } task; <span class="comment">/*!&lt; FreeRTOS 任务设置.*/</span></span><br><span class="line">  <span class="comment">/**</span></span><br><span class="line"><span class="comment">   * Client 用户缓冲区大小设置</span></span><br><span class="line"><span class="comment">   *</span></span><br><span class="line"><span class="comment">   * Client 有两个缓冲区：输入和输出缓冲区</span></span><br><span class="line"><span class="comment">   */</span></span><br><span class="line">  <span class="class"><span class="keyword">struct</span> <span class="title">buffer_t</span> {</span></span><br><span class="line">      <span class="type">int</span> size;     <span class="comment">/*!&lt; size of *MQTT* send/receive buffer*/</span></span><br><span class="line">      <span class="type">int</span> out_size; <span class="comment">/*!&lt; size of *MQTT* output buffer. If not defined, defaults to the size defined by</span></span><br><span class="line"><span class="comment">              ``buffer_size`` */</span></span><br><span class="line">  } buffer; <span class="comment">/*!&lt; Buffer size configuration.*/</span></span><br><span class="line">} <span class="type">esp_mqtt_client_config_t</span>;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<ul>
<li>使用 uri 字段的格式为<code> scheme://hostname:port/path</code></li>
</ul>
<ul>
<li><p>当前支持 <code>mqtt</code>、<code>mqtts</code>、<code>ws</code> 和 <code>wss</code> 协议</p>
</li>
<li><p>基于 TCP 的 MQTT 示例：</p>
<ul>
<li><p><code>mqtt://mqtt.eclipseprojects.io</code>：基于 TCP 的 MQTT，默认端口 1883</p>
</li>
<li><p><code>mqtt://mqtt.eclipseprojects.io:1884</code>：基于 TCP 的 MQTT，端口 1884</p>
</li>
<li><p><code>mqtt://username:password@mqtt.eclipseprojects.io:1884</code>：基于 TCP 的 MQTT， 端口 1884，带有用户名和密码</p>
</li>
</ul>
</li>
<li><p>基于 SSL 的 MQTT 示例：</p>
<ul>
<li><p><code>mqtts://mqtt.eclipseprojects.io</code>：基于 SSL 的 MQTT，端口 8883</p>
</li>
<li><p><code>mqtts://mqtt.eclipseprojects.io:8884</code>：基于 SSL 的 MQTT，端口 8884</p>
</li>
</ul>
</li>
<li><p>基于 WebSocket 的 MQTT 示例：</p>
<ul>
<li><code>ws://mqtt.eclipseprojects.io:80/mqtt</code></li>
</ul>
</li>
<li><p>基于 WebSocket Secure 的 MQTT 示例：</p>
<ul>
<li><code>wss://mqtt.eclipseprojects.io:443/mqtt</code></li>
</ul>
</li>
</ul>
<ul>
<li><p>客户端凭据<br>  <code>credentials</code> 字段下包含所有客户端相关凭据。</p>
<ul>
<li><p><code>username</code>：指向用于连接服务器用户名的指针，也可通过 URI 设置</p>
</li>
<li><p><code>client_id</code>：指向客户端 ID 的指针，默认为 ESP32_%CHIPID%，其中 %CHIPID% 是十六进制 MAC 地址的最后 3 个字节</p>
</li>
</ul>
<p>  认证<br>  可以通过 <code>authentication</code> 字段设置认证参数。客户端支持以下认证方式：</p>
<ul>
<li><p><code>password</code>：使用密码</p>
</li>
<li><p><code>certificate</code> 和 <code>key</code>：进行双向 TLS 身份验证，PEM 或 DER 格式均可</p>
</li>
<li><p><code>use_secure_element</code>：使用 ESP32-WROOM-32SE 中的安全元素</p>
</li>
<li><p><code>ds_data</code>：使用某些乐鑫设备的数字签名外设</p>
</li>
</ul>
</li>
</ul>
<blockquote>
<p><strong>MQTT 协议中的 Keep Alive 机制</strong></p>
<p><a target="_blank" rel="noopener" href="https://www.emqx.com/zh/mqtt">MQTT 协议</a>是承载于 TCP 协议之上的，而 TCP 协议以连接为导向，在连接双方之间，提供稳定、有序的字节流功能。 但是，在部分情况下，TCP 可能出现半连接问题。所谓半连接，是指某一方的连接已经断开或者没有建立，而另外一方的连接却依然维持着。在这种情况下，半连接的一方可能会持续不断地向对端发送数据，而显然这些数据永远到达不了对端。为了避免半连接导致的通信黑洞，<a target="_blank" rel="noopener" href="https://www.emqx.com/zh/mqtt">MQTT 协议</a>提供了 <strong>Keep Alive</strong> 机制，使客户端和 <a target="_blank" rel="noopener" href="https://www.emqx.io/zh">MQTT 服务器</a>可以判定当前是否存在半连接问题，从而关闭对应连接。</p>
</blockquote>
<blockquote>
<p><strong>MQTT持久会话与Clean Session详解</strong></p>
<p>MQTT客户端在发起服务器连接时，可以设置是否创建一个持久会话。但Clean Session为true，指在创建一个新的会话时，在客户端断开连接时会话会自动销毁，为false时，在客户端断开连接时会话仍然保持，直到其重新连接或者会话超时注销。</p>
<p>持久会话可以避免因网络中断导致的重复订阅或者错过离线期间的消息。</p>
</blockquote>
<h3 id="注册事件函数"><a href="#注册事件函数" class="headerlink" title="注册事件函数"></a>注册事件函数</h3><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">esp_err_t</span> <span class="title function_">esp_mqtt_client_register_event</span><span class="params">(<span class="type">esp_mqtt_client_handle_t</span> client, <span class="type">esp_mqtt_event_id_t</span> event, <span class="type">esp_event_handler_t</span> event_handler, <span class="type">void</span> *event_handler_arg)</span></span><br></pre></td></tr></table></figure>

<p>使用该函数注册事件处理函数。该事件处理的用法与esp_event库相似。</p>
<p>一个标准的事件处理模板为：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> * @brief Event handler registered to receive MQTT events</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> *  This function is called by the MQTT client event loop.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * @param handler_args user data registered to the event.</span></span><br><span class="line"><span class="comment"> * @param base Event base for the handler(always MQTT Base in this example).</span></span><br><span class="line"><span class="comment"> * @param event_id The id for the received event.</span></span><br><span class="line"><span class="comment"> * @param event_data The data for the event, esp_mqtt_event_handle_t.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">mqtt_event_handler</span><span class="params">(<span class="type">void</span> *handler_args, <span class="type">esp_event_base_t</span> base, <span class="type">int32_t</span> event_id, <span class="type">void</span> *event_data)</span></span><br><span class="line">{</span><br><span class="line">    ESP_LOGD(TAG, <span class="string">"Event dispatched from event loop base=%s, event_id=%d"</span>, base, event_id);</span><br><span class="line">    <span class="type">esp_mqtt_event_handle_t</span> event = event_data;</span><br><span class="line">    <span class="type">esp_mqtt_client_handle_t</span> client = event-&gt;client;</span><br><span class="line">    <span class="type">int</span> msg_id;</span><br><span class="line">    <span class="keyword">switch</span> ((<span class="type">esp_mqtt_event_id_t</span>)event_id) {</span><br><span class="line">    <span class="keyword">case</span> MQTT_EVENT_CONNECTED:</span><br><span class="line">        ESP_LOGI(TAG, <span class="string">"MQTT_EVENT_CONNECTED"</span>);</span><br><span class="line">        msg_id = esp_mqtt_client_publish(client, <span class="string">"/topic/qos1"</span>, <span class="string">"data_3"</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="number">0</span>);</span><br><span class="line">        ESP_LOGI(TAG, <span class="string">"sent publish successful, msg_id=%d"</span>, msg_id);</span><br><span class="line"></span><br><span class="line">        msg_id = esp_mqtt_client_subscribe(client, <span class="string">"/topic/qos0"</span>, <span class="number">0</span>);</span><br><span class="line">        ESP_LOGI(TAG, <span class="string">"sent subscribe successful, msg_id=%d"</span>, msg_id);</span><br><span class="line"></span><br><span class="line">        msg_id = esp_mqtt_client_subscribe(client, <span class="string">"/topic/qos1"</span>, <span class="number">1</span>);</span><br><span class="line">        ESP_LOGI(TAG, <span class="string">"sent subscribe successful, msg_id=%d"</span>, msg_id);</span><br><span class="line"></span><br><span class="line">        msg_id = esp_mqtt_client_unsubscribe(client, <span class="string">"/topic/qos1"</span>);</span><br><span class="line">        ESP_LOGI(TAG, <span class="string">"sent unsubscribe successful, msg_id=%d"</span>, msg_id);</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">    <span class="keyword">case</span> MQTT_EVENT_DISCONNECTED:</span><br><span class="line">        ESP_LOGI(TAG, <span class="string">"MQTT_EVENT_DISCONNECTED"</span>);</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">case</span> MQTT_EVENT_SUBSCRIBED:</span><br><span class="line">        ESP_LOGI(TAG, <span class="string">"MQTT_EVENT_SUBSCRIBED, msg_id=%d"</span>, event-&gt;msg_id);</span><br><span class="line">        msg_id = esp_mqtt_client_publish(client, <span class="string">"/topic/qos0"</span>, <span class="string">"data"</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>);</span><br><span class="line">        ESP_LOGI(TAG, <span class="string">"sent publish successful, msg_id=%d"</span>, msg_id);</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">    <span class="keyword">case</span> MQTT_EVENT_UNSUBSCRIBED:</span><br><span class="line">        ESP_LOGI(TAG, <span class="string">"MQTT_EVENT_UNSUBSCRIBED, msg_id=%d"</span>, event-&gt;msg_id);</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">    <span class="keyword">case</span> MQTT_EVENT_PUBLISHED:</span><br><span class="line">        ESP_LOGI(TAG, <span class="string">"MQTT_EVENT_PUBLISHED, msg_id=%d"</span>, event-&gt;msg_id);</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">    <span class="keyword">case</span> MQTT_EVENT_DATA:</span><br><span class="line">        ESP_LOGI(TAG, <span class="string">"MQTT_EVENT_DATA"</span>);</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">"TOPIC=%.*s\r\n"</span>, event-&gt;topic_len, event-&gt;topic);</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">"DATA=%.*s\r\n"</span>, event-&gt;data_len, event-&gt;data);</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">    <span class="keyword">case</span> MQTT_EVENT_ERROR:</span><br><span class="line">        ESP_LOGI(TAG, <span class="string">"MQTT_EVENT_ERROR"</span>);</span><br><span class="line">        <span class="keyword">if</span> (event-&gt;error_handle-&gt;error_type == MQTT_ERROR_TYPE_TCP_TRANSPORT) {</span><br><span class="line">            log_error_if_nonzero(<span class="string">"reported from esp-tls"</span>, event-&gt;error_handle-&gt;esp_tls_last_esp_err);</span><br><span class="line">            log_error_if_nonzero(<span class="string">"reported from tls stack"</span>, event-&gt;error_handle-&gt;esp_tls_stack_err);</span><br><span class="line">            log_error_if_nonzero(<span class="string">"captured as transport's socket errno"</span>,  event-&gt;error_handle-&gt;esp_transport_sock_errno);</span><br><span class="line">            ESP_LOGI(TAG, <span class="string">"Last errno string (%s)"</span>, strerror(event-&gt;error_handle-&gt;esp_transport_sock_errno));</span><br><span class="line"></span><br><span class="line">        }</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">    <span class="keyword">default</span>:</span><br><span class="line">        ESP_LOGI(TAG, <span class="string">"Other event id:%d"</span>, event-&gt;event_id);</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">    }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//示例注册函数</span></span><br><span class="line">esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, <span class="literal">NULL</span>);</span><br><span class="line"></span><br></pre></td></tr></table></figure>



<h3 id="开始MQTT客户端"><a href="#开始MQTT客户端" class="headerlink" title="开始MQTT客户端"></a>开始MQTT客户端</h3><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">esp_err_t</span> <span class="title function_">esp_mqtt_client_start</span><span class="params">(<span class="type">esp_mqtt_client_handle_t</span> client)</span>;</span><br></pre></td></tr></table></figure>

<p>开启MQTT客户端服务。</p>
<h3 id="订阅-x2F-取消订阅"><a href="#订阅-x2F-取消订阅" class="headerlink" title="订阅/取消订阅"></a>订阅/取消订阅</h3><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">esp_mqtt_client_subscribe</span><span class="params">(<span class="type">esp_mqtt_client_handle_t</span> client, <span class="type">const</span> <span class="type">char</span> *topic, <span class="type">int</span> qos)</span></span><br></pre></td></tr></table></figure>

<p>将客户端订阅到定义的主题，并定义了QOS。需要在连接服务器后进行。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">esp_mqtt_client_unsubscribe</span><span class="params">(<span class="type">esp_mqtt_client_handle_t</span> client, <span class="type">const</span> <span class="type">char</span> *topic)</span></span><br></pre></td></tr></table></figure>

<p>取消订阅。</p>
<h3 id="发布内容"><a href="#发布内容" class="headerlink" title="发布内容"></a>发布内容</h3><p>ESP提供了两种发布内容的方法，阻塞式和非阻塞。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">esp_mqtt_client_publish</span><span class="params">(<span class="type">esp_mqtt_client_handle_t</span> client, <span class="type">const</span> <span class="type">char</span> *topic, <span class="type">const</span> <span class="type">char</span> *data, <span class="type">int</span> len, <span class="type">int</span> qos, <span class="type">int</span> retain)</span>;</span><br></pre></td></tr></table></figure>

<p><strong>阻塞式发布一个消息。超时时间为config中的网络超时时间。使用这个API不需要先连接到服务器，此时消息会自动加入后台队列(如果设置了MQTT_SKIP_PUBLISH_IF_DISCONNECTED为true，则不会尝试发送而是直接返回-1)</strong></p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">esp_mqtt_client_enqueue</span><span class="params">(<span class="type">esp_mqtt_client_handle_t</span> client, <span class="type">const</span> <span class="type">char</span> *topic, <span class="type">const</span> <span class="type">char</span> *data, <span class="type">int</span> len, <span class="type">int</span> qos, <span class="type">int</span> retain, <span class="type">bool</span> store)</span></span><br></pre></td></tr></table></figure>

<p>将信息排队到outbox，以便<strong>稍后发送</strong>。<strong>通常用于qos&gt;0的消息，但如果store=true，也可用于qos=0的消息</strong>。</p>
<p>这个API生成并存储发布消息到内部的outbox中，而实际发送至网络是在mqtt任务中进行的（与esp_mqtt_client_publish()相反，后者在用户任务的任务中立即发送发布消息）。因此，它可以作为esp_mqtt_client_publish()的一个非阻塞版本。</p>
<blockquote>
<p>QOS服务质量</p>
<ul>
<li>QoS0，At most once，至多一次,Sender 发送的一条消息，Receiver 最多能收到一次，也就是说 Sender 尽力向 Receiver 发送消息，如果发送失败，也就算了；</li>
<li>QoS1，At least once，至少一次,Sender 发送的一条消息，Receiver 至少能收到一次，也就是说 Sender 向 Receiver 发送消息，如果发送失败，会继续重试，直到 Receiver 收到消息为止，但是因为重传的原因，Receiver 有可能会收到重复的消息；</li>
<li>QoS2，Exactly once，确保只有一次,Sender 发送的一条消息，Receiver 确保能收到而且只收到一次，也就是说 Sender 尽力向 Receiver 发送消息，如果发送失败，会继续重试，直到 Receiver 收到消息为止，同时保证 Receiver 不会因为消息重传而收到重复的消息。</li>
</ul>
</blockquote>
<blockquote>
<p>当我们使用MQTT客户端发布消息（<code>PUBLISH</code>）时，如果将RETAIN标志位设置为<code>true</code>，那么MQTT服务器会将最近收到的一条RETAIN标志位为<code>true</code>的消息保存在服务器端（内存或文件）。<br><strong>特别注意：MQTT服务器只会为每一个Topic保存最近收到的一条RETAIN标志位为<code>true</code>的消息！也就是说，如果MQTT服务器上已经为某个Topic保存了一条Retained消息，当客户端再次发布一条新的Retained消息，那么服务器上原来的那条消息会被覆盖！</strong></p>
<p><strong>每当MQTT客户端连接到MQTT服务器并订阅了某个topic，如果该topic下有Retained消息，那么MQTT服务器会立即向客户端推送该条Retained消息。</strong></p>
<p>如果客户端想让MQTT服务器删除某个Topic下保存的Retained消息，唯一的方法是向MQTT服务器发布一条RETAIN标志位为<code>true</code>的<strong>空消息</strong>。<br><strong>空消息</strong>即为发布消息（<code>PUBLISH</code>）的时候，Payload中设置0个字节的内容。<br>删除了某个Topic下保存的Retained消息，如果客户端没有再发布Retained消息，则MQTT服务器上对于该Topic就没有了Retained消息。</p>
</blockquote>
<h3 id="其他API"><a href="#其他API" class="headerlink" title="其他API"></a>其他API</h3><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">esp_err_t</span> <span class="title function_">esp_mqtt_client_set_uri</span><span class="params">(<span class="type">esp_mqtt_client_handle_t</span> client, <span class="type">const</span> <span class="type">char</span> *uri)</span>;</span><br></pre></td></tr></table></figure>

<p>更新uri。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">esp_err_t</span> <span class="title function_">esp_mqtt_client_reconnect</span><span class="params">(<span class="type">esp_mqtt_client_handle_t</span> client)</span>;</span><br></pre></td></tr></table></figure>

<p>手动重新连接。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">esp_err_t</span> <span class="title function_">esp_mqtt_client_disconnect</span><span class="params">(<span class="type">esp_mqtt_client_handle_t</span> client)</span>;</span><br></pre></td></tr></table></figure>

<p>手动断连。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">esp_err_t</span> <span class="title function_">esp_mqtt_set_config</span><span class="params">(<span class="type">esp_mqtt_client_handle_t</span> client, <span class="type">const</span> <span class="type">esp_mqtt_client_config_t</span> *config)</span>;</span><br></pre></td></tr></table></figure>

<p>更新设置，在<code>MQTT_EVENT_BEFORE_CONNECT</code>前。</p>
<h2 id="三，其他参考"><a href="#三，其他参考" class="headerlink" title="三，其他参考"></a>三，其他参考</h2><h3 id="事件参考"><a href="#事件参考" class="headerlink" title="事件参考"></a>事件参考</h3><p>User event handler receives context data in <code>esp_mqtt_event_t</code> structure with</p>
<p><strong><code>client</code> - MQTT client handle</strong></p>
<p><strong>various other data depending on event type</strong></p>
<ul>
<li><p><code>MQTT_EVENT_ANY</code></p>
</li>
<li><p><code>MQTT_EVENT_ERROR</code></p>
<p>  在错误事件中，额外的上下文：连接返回代码，来自esp_tls的错误处理（如果支持）</p>
</li>
<li><p><code>MQTT_EVENT_CONNECTED</code></p>
<p>  connected event, additional context: session_present flag</p>
</li>
<li><p><code>MQTT_EVENT_DISCONNECTED</code></p>
<p>  disconnected event</p>
</li>
<li><p><code>MQTT_EVENT_SUBSCRIBED</code></p>
<p>  subscribed event, additional context:</p>
<ul>
<li><p><code>msg_id</code> message id</p>
</li>
<li><p><code>error_handle</code> error_type in case subscribing failed</p>
</li>
<li><p><code>data</code> pointer to broker response, check for errors.</p>
</li>
<li><p><code>data_len</code> length of the data for this event</p>
</li>
</ul>
</li>
<li><p><code>MQTT_EVENT_UNSUBSCRIBED</code></p>
<p>  unsubscribed event, additional context: msg_id</p>
</li>
<li><p><code>MQTT_EVENT_PUBLISHED</code></p>
<p>  published event, additional context: msg_id</p>
</li>
<li><p><code>MQTT_EVENT_DATA</code></p>
<p>  data event, additional context:</p>
<ul>
<li><p><code>msg_id</code> message id</p>
</li>
<li><p><code>topic</code> pointer to the received topic</p>
</li>
<li><p><code>topic_len</code> length of the topic</p>
</li>
<li><p><code>data</code> pointer to the received data</p>
</li>
<li><p><code>data_len</code> length of the data for this event</p>
</li>
<li><p><code>current_data_offset</code> offset of the current data for this event</p>
</li>
<li><p><code>total_data_len total</code> length of the data received</p>
</li>
<li><p><code>retain</code> retain flag of the message</p>
</li>
<li><p><code>qos</code> QoS level of the message</p>
</li>
<li><p><code>dup</code> dup flag of the message Note: Multiple MQTT_EVENT_DATA could be fired for one message, if it is longer than internal buffer. In that case only first event contains topic pointer and length, other contain data only with current data length and current data offset updating.</p>
</li>
</ul>
</li>
<li><p><code>MQTT_EVENT_BEFORE_CONNECT</code></p>
<p>  The event occurs before connecting</p>
</li>
<li><p><code>MQTT_EVENT_DELETED</code></p>
<p>  Notification on delete of one message from the internal outbox, if the message couldn’t have been sent and acknowledged before expiring defined in OUTBOX_EXPIRED_TIMEOUT_MS. (events are not posted upon deletion of successfully acknowledged messages)</p>
<ul>
<li>This event id is posted only if MQTT_REPORT_DELETED_MESSAGES==1</li>
<li>Additional context: msg_id (id of the deleted message).</li>
</ul>
</li>
<li><p><code>MQTT_USER_EVENT</code></p>
<p>  Custom event used to queue tasks into mqtt event handler All fields from the <a target="_blank" rel="noopener" href="https://docs.espressif.com/projects/esp-idf/zh_CN/latest/esp32s3/api-reference/protocols/mqtt.html#structesp__mqtt__event__t">esp_mqtt_event_t</a> type could be used to pass an additional context data to the handler.</p>
</li>
</ul>

        </div>
        
<blockquote class="copyright">
    <p><strong>本文链接 : </strong><a class="permalink" href="https://lostacnet.top/post/5349/">https://lostacnet.top/post/5349/</a></p>
    <p><strong>This article is available under <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank" rel="noopener noreferrer">Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0)</a> License  转载请注明出处</strong></p>
</blockquote>


    </article>
    
    <section id="comments">
        
    </section>


    

</main>


<aside style="" id="sidebar" class="aside aside-fixture">
    <div class="toc-sidebar">
        <nav id="toc" class="article-toc">
            <h3 class="toc-title">文章目录</h3>
            <ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%B8%80%EF%BC%8CMQTT%E5%8D%8F%E8%AE%AE%E7%9A%84%E7%AE%80%E4%BB%8B"><span class="toc-number">1.</span> <span class="toc-text">一，MQTT协议的简介</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%BA%8C%EF%BC%8CESP-MQTT%E7%9A%84%E9%85%8D%E7%BD%AE%E8%BF%87%E7%A8%8B"><span class="toc-number">2.</span> <span class="toc-text">二，ESP_MQTT的配置过程</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%88%9D%E5%A7%8B%E5%8C%96MQTT"><span class="toc-number">2.1.</span> <span class="toc-text">初始化MQTT</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%B3%A8%E5%86%8C%E4%BA%8B%E4%BB%B6%E5%87%BD%E6%95%B0"><span class="toc-number">2.2.</span> <span class="toc-text">注册事件函数</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%BC%80%E5%A7%8BMQTT%E5%AE%A2%E6%88%B7%E7%AB%AF"><span class="toc-number">2.3.</span> <span class="toc-text">开始MQTT客户端</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%AE%A2%E9%98%85-x2F-%E5%8F%96%E6%B6%88%E8%AE%A2%E9%98%85"><span class="toc-number">2.4.</span> <span class="toc-text">订阅&#x2F;取消订阅</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%8F%91%E5%B8%83%E5%86%85%E5%AE%B9"><span class="toc-number">2.5.</span> <span class="toc-text">发布内容</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%85%B6%E4%BB%96API"><span class="toc-number">2.6.</span> <span class="toc-text">其他API</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%B8%89%EF%BC%8C%E5%85%B6%E4%BB%96%E5%8F%82%E8%80%83"><span class="toc-number">3.</span> <span class="toc-text">三，其他参考</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E4%BA%8B%E4%BB%B6%E5%8F%82%E8%80%83"><span class="toc-number">3.1.</span> <span class="toc-text">事件参考</span></a></li></ol></li></ol>
        </nav>
    </div>
</aside>





        </section>
        <footer class="hidden lg:block fixed bottom-0 left-0 sm:w-1/12 lg:w-1/6 bg-gray-100 z-40">
    
    <div class="footer-social-links">
        
            <a target="_blank" rel="noopener" href="https://github.com/LOStacNet">
                <i class="iconfont icon-github"></i>
            </a>
        
            <a target="_blank" rel="noopener" href="https://gitee.com/LOStacNet">
                <i class="iconfont icon-project"></i>
            </a>
        
    </div>
    
    
</footer>

        <div id="mask" class="hidden mask fixed inset-0 bg-gray-900 opacity-75 z-40"></div>
        <div id="search-view-container" class="hidden shadow-xl"></div>
        
<script src="/js/dom-event.min.js"></script>



<script src="/js/local-search.min.js"></script>



    <script src="//cdn.jsdelivr.net/npm/lightgallery.js@1.1.3/dist/js/lightgallery.min.js"></script>
    
<script src="/js/light-gallery.min.js"></script>






    </body>
</html>
